package com.example.software.config;

import com.example.software.filter.JwtAuthenticationFilter;
import com.example.software.vo.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
    
    @Autowired
    private ObjectMapper objectMapper;

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }
    
    /**
     * 自定义认证失败处理
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                String uri = request.getRequestURI();
                String method = request.getMethod();
                log.error("认证失败: {} - 请求路径: {}, 方法: {}", e.getMessage(), uri, method);
                
                // 获取用户类型（如果在请求属性中）
                Object userType = request.getAttribute("userType");
                if (userType != null) {
                    log.info("认证失败但存在用户类型: {}", userType);
                }
                
                // 获取认证头信息进行记录，但不泄露完整token
                String authHeader = request.getHeader("Authorization");
                boolean hasAuthHeader = authHeader != null && !authHeader.isEmpty();
                log.info("请求是否包含认证头: {}", hasAuthHeader);
                
                // 特殊处理任务创建请求
                boolean isTaskCreate = method.equals("POST") && uri.equals("/api/tasks");
                if (isTaskCreate) {
                    log.error("任务创建请求认证失败");
                }
                
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                response.setCharacterEncoding("UTF-8");
                
                Result<Void> result;
                if (isTaskCreate) {
                    result = Result.error(401, "任务创建需要认证：" + e.getMessage());
                } else {
                    result = Result.error(401, "认证失败: " + e.getMessage());
                }
                
                PrintWriter writer = response.getWriter();
                writer.write(objectMapper.writeValueAsString(result));
                writer.flush();
            }
        };
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 添加一条日志
        log.info("配置安全设置");
        
        http
                // 禁用 CSRF
                .csrf().disable()
                // 启用CORS
                .cors().and()
                // 不通过Session获取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 对于登录注册接口，允许匿名访问
                .antMatchers("/api/auth/**").permitAll()
                // GET请求任务列表允许匿名访问
                .antMatchers(HttpMethod.GET, "/api/tasks").permitAll()
                // 任务创建需要企业用户权限
                .antMatchers(HttpMethod.POST, "/api/tasks").hasRole("COMPANY")
                // 所有其他请求需要完整认证
                .anyRequest().authenticated()
                .and()
                // 添加自定义认证失败处理
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint());

        // 添加JWT filter，确保它在UsernamePasswordAuthenticationFilter之前执行
        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        
        log.info("安全配置完成");
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Requested-With"));
        configuration.setExposedHeaders(Arrays.asList("Authorization"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
} 